package me.zhangsanfeng.gpss.common.filter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import me.zhangsanfeng.gpss.common.entity.BaseException;
import me.zhangsanfeng.gpss.common.entity.JwtProperty;
import me.zhangsanfeng.gpss.common.utils.DataUtil;
import me.zhangsanfeng.gpss.common.utils.JsonUtil;
import me.zhangsanfeng.gpss.common.utils.JwtUtil;
import me.zhangsanfeng.gpss.common.utils.ResultUtil;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;

/**
 * @ClassName:JWTAuthenticationFilter
 * @Description:对token进行校验
 * @Author:ZhangYao
 * @Date:2018/11/5 22:32
 * @Version:1.0
 */
@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    private JwtProperty jwtProperty;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager ,
                                   JwtProperty JwtProperty) {
        super(authenticationManager);
        this.jwtProperty = JwtProperty;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        String authorization = request.getHeader("Authorization");
        // 放行GET请求
        if (request.getMethod().equals(String.valueOf(RequestMethod.GET))) {
            chain.doFilter(request, response);
            return;
        }
        //未提供token
        if (DataUtil.isEmpty(authorization) ){
            String url = request.getRequestURL().toString();
            //新增用户除外
            if (url.endsWith("signup")){
                chain.doFilter(request,response);
                return;
            }
            response.getWriter().write(JsonUtil.toJsonString(ResultUtil.forbidden("未提供token")));
            return;
        }
        // Token格式错误
        if (!authorization.startsWith("Bearer ")) {
            response.getWriter().write(JsonUtil.toJsonString(ResultUtil.forbidden("token格式错误")));
            return;
        }
        String token = authorization.replace("Bearer ", "");
        Claims claims = null;
        //token超时
        try {
            claims = JwtUtil.parseToken(token, jwtProperty.getBase64Security());
        } catch (Exception e) {
            response.getWriter().write(JsonUtil.toJsonString(ResultUtil.forbidden(e.getMessage())));
            return;
        }

        if (null == claims){
            response.getWriter().write(JsonUtil.toJsonString(ResultUtil.forbidden("token解析失败")));
            return;
        }
        if (DataUtil.isEmpty(claims.get("username"))){
            response.getWriter().write(JsonUtil.toJsonString(ResultUtil.forbidden("无效的token")));
            return;
        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(authorization);

        SecurityContextHolder.getContext().setAuthentication(authentication);

        chain.doFilter(request,response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(String authorization) {
        String token = authorization.replace("Bearer ", "");
        Claims claims = null;
        try {
            claims = JwtUtil.parseToken(token, jwtProperty.getBase64Security());
        } catch (Exception e) {
            throw new BaseException(e.getMessage());
        }

        if (DataUtil.isNotEmpty(claims)){
            String username = claims.get("username").toString();
            return new UsernamePasswordAuthenticationToken(username,null, Collections.emptyList());
        }
        return null;
    }
}
